#include <atomic>

#include <hude/utils/parses.hpp>
#include <hude/base/log.hpp>

#include "plugs/plug.hpp"
#include "virt-x2000.hpp"

namespace ha
{
    namespace brick
    {
        namespace pl =  std::placeholders;

        /*********************************************************************
         * @brief 虚拟x2000模块
         */
        class x2k_t :
            public brick_t
        {
        public:
            //声明解析栈类型
            using parses_t = hude::utils::parses_t<>;

        public:
            x2k_t( aio_t aio, const json_t& args ) : aio_( aio ), parsing_( false )
            {
                if( ! this->settings( args ) || ! init() )
                {
                    llog_err( "<plug-x2000>", "ERROR: pulg init: x2000" );
                }
            }

            ~x2k_t()
            {
                deinit();
            }

            int send( const void* p, size_t n ) override { _recv( p, n ); return n; }

            void close() override { deinit(); }

            bool settings( const json_t& args ) override;

        private:
            void parse();

            bool init();
            void deinit();

            void _recv( const void*, size_t );

            bool on_frame( parses_t::citr_t&, parses_t::citr_t&, bool& );

        private:
            aio_t            aio_;
            parses_t         parses_;
            uhf_t            uhf_;
            std::atomic_flag parsing_;
        };

        /*********************************************************************
         * @brief 设置参数
         */
        inline bool x2k_t::settings( const json_t& args )
        {
            // llog_dug( "<plug-x2000>", "\t\t config rfid: %s", args.dump().c_str() );

            return uhf_.on_config( args );
        }

        /*********************************************************************
         * @brief 接收数据
         */
        void x2k_t::_recv( const void* p, size_t n )
        {
            parses_.buffer_push( p, n );

            aio_->task_commit( [=]{ this->parse(); } );
        }

        /*********************************************************************
         * @brief 初始化
         */
        bool x2k_t::init()
        {
            parses_.observer_pre( std::bind( &x2k_t::on_frame, this, pl::_1, pl::_2,  pl::_3 ) );

            return true;
        }

        /*********************************************************************
         * @brief 反初始化
         */
        void x2k_t::deinit()
        {
        }

        /*********************************************************************
         * @brief 解析缓冲中存在的所有数据
         */
        void x2k_t::parse()
        {
            // 无效数据丢弃事件
            auto drop = []( parses_t::citr_t b, parses_t::citr_t e ) -> void
            {
                llog_war( "<plug-x2000>", "\t\t droped bytes: %u(%s)", e - b, hude::utils::to_hex( &(*b), e - b ).c_str() );
            };

            if( ! parsing_.test_and_set() )
            {
                parses_.parse_all( &pgl::x2000::packet_t::find< parses_t::citr_t >, drop );

                parsing_.clear();
            }
        }

        /*********************************************************************
         * @brief 桢订阅处理函数
         *      参数b和e为数据桢处于缓冲区的头尾区间
         *      返回值为是否停止路由给解析栈的下一个订阅函数, true为停止
         */
        bool x2k_t::on_frame( parses_t::citr_t& b, parses_t::citr_t& e, bool& )
        {
            auto cb = [=]( const hude::buffer_t& buffer )
            {
                if( this->cb_recv_ ) this->cb_recv_( buffer );
            };

            uhf_.on_handle( cb, b, e );

            return true;
        }

    } //namespace brick
} //namespace ha

/*********************************************************************
 * @brief 工厂函数 
 */
EXTERN_C ha::pbrick_t _factory_brick( ha::aio_t aio, const ha::json_t& cfg )
{
    return ha::pbrick_t( new ha::brick::x2k_t{ aio, cfg } );
}